//
// Created by zsj on 2019/12/21.
//

#ifndef SCLI_DES_CRYPTO_H
#define SCLI_DES_CRYPTO_H

#include <iostream>
#include "crypto_algorithm.h"
#include "openssl/des.h"
#include <cstring>
#include <vector>
#include <cmath>

class des_crypto : public crypto_algorithm {
public:
    virtual const string encrypt() {
        DES_cblock key_encrypt;
        memset(key_encrypt, 0, 8);

        memcpy(key_encrypt, key.c_str(), min((int) key.length(), 8));

        DES_key_schedule key_schedule;
        DES_set_key_unchecked(&key_encrypt, &key_schedule);

        const_DES_cblock input;
        DES_cblock output;
        vector<unsigned char> v_cipher;
        unsigned char buf[8];

        for (int i = 0; i < plain.length() / 8; i++) {
            memcpy(input, plain.c_str() + i * 8, 8);
            DES_ecb_encrypt(&input, &output, &key_schedule, DES_ENCRYPT);
            memcpy(buf, output, 8);

            for (unsigned char j : buf) {
                v_cipher.push_back(j);
            }
        }

        // 边界填充
        if (plain.length() % 8 != 0) {
            int tmp1 = plain.length() / 8 * 8;
            int rest_len = plain.length() - tmp1;

            // 填充剩余的位
            string rest = plain.substr(tmp1);
            for (int i = 0; i < 8 - rest_len; i++) {
                rest += (char) (8 - rest_len);
            }

            memset(input, 0, 8);
            memcpy(input, rest.c_str(), 8);
            // 加密函数
            DES_ecb_encrypt(&input, &output, &key_schedule, DES_ENCRYPT);
            memcpy(buf, output, 8);

            for (unsigned char j : buf) {
                v_cipher.push_back(j);
            }
        } else {
            string rest = "";
            for (int i = 0; i < 8; i++) {
                rest += (char) 8;
            }

            memset(input, 0, 8);
            memcpy(input, rest.c_str(), 8);
            // 加密函数
            DES_ecb_encrypt(&input, &output, &key_schedule, DES_ENCRYPT);
            memcpy(buf, output, 8);

            for (unsigned char j : buf) {
                v_cipher.push_back(j);
            }
        }

        cipher.clear();
        cipher.assign(v_cipher.begin(), v_cipher.end());

        return cipher;
    }

    virtual const string decrypt() {
        DES_cblock key_encrypt;
        memset(key_encrypt, 0, 8);

        memcpy(key_encrypt, key.c_str(), min((int) key.length(), 8));

        DES_key_schedule key_schedule;
        DES_set_key_unchecked(&key_encrypt, &key_schedule);

        const_DES_cblock input;
        DES_cblock output;
        vector<unsigned char> v_plain;
        unsigned char buf[8];

        for (int i = 0; i < cipher.length() / 8; i++) {
            memcpy(input, cipher.c_str() + i * 8, 8);
            DES_ecb_encrypt(&input, &output, &key_schedule, DES_DECRYPT);
            memcpy(buf, output, 8);

            for (unsigned char j : buf) {
                v_plain.push_back(j);
            }
        }

        if (cipher.length() % 8 != 0) {
            int tmp1 = cipher.length() / 8 * 8;
            int tmp2 = cipher.length() - tmp1;
            memset(input, 0, 8);
            memcpy(input, cipher.c_str() + tmp1, tmp2);
            // 加密函数
            DES_ecb_encrypt(&input, &output, &key_schedule, DES_DECRYPT);
            memcpy(buf, output, 8);

            for (unsigned char j : buf) {
                v_plain.push_back(j);
            }
        }

        plain.clear();
        plain.assign(v_plain.begin(), v_plain.end());

        // 去除边界
        char c = plain[plain.length() - 1];
        plain = plain.substr(0, plain.length() - c);

        return plain;
    }

    des_crypto() {

    }

    ~des_crypto() {}
};

#endif //SCLI_DES_CRYPTO_H
